package week13.week_13_client;

import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.rmi.server.ExportException;
import java.util.ArrayList;
import java.util.HashMap;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import week13.week_13_server.*;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class LoginGUI extends Application {
    TextField tf_msg;
    TextArea ta_info;
    DatagramSocket socket = null;
    ArrayList onlineUser=new ArrayList();
    SSLSocketFactory factory=null;
    ObservableList observableList;
    ListView<String> listView;
    Socket s;
    User user;
    Button btn_sendFile;
    FileChooser fileChooser = new FileChooser();
    Button btn_listFile;

    public LoginGUI(Socket s,SSLSocketFactory factory,User user) throws Exception{
        this.user=user;
        this.s = s;
        this.factory = factory;
        init();
        if(connect())
            start(new Stage());
        else {
            MyUtils.showAlert("连接服务器出错！");
        }
    }

    @Override
    public void start(Stage stage) throws Exception {
        // TODO Auto-generated method stub
        GridPane pane_com = new GridPane();
        Label lb_msg = new Label("Message:");
        tf_msg = new TextField();
        tf_msg.setPrefColumnCount(20);
        Button btn_send = new Button("   Send  ");
        btn_sendFile = new Button("  发送文件  ");
        btn_sendFile.setOnAction(event -> {
            ObservableList selectedIndices = listView.getSelectionModel().getSelectedItems();
            for(Object o : selectedIndices){
                sendFile(o.toString());
            }
        });
        btn_send.setOnAction(event -> {
            ObservableList selectedIndices = listView.getSelectionModel().getSelectedItems();
            for(Object o : selectedIndices){
                sentTo(o.toString());
            }
        });

        btn_listFile = new Button("接收文件");
        btn_listFile.setOnAction(this::listFile);

        pane_com.addRow(1, lb_msg, tf_msg, btn_send);
        pane_com.addRow(2,btn_sendFile,btn_listFile);
        GridPane.setHalignment(lb_msg,HPos.RIGHT);
        pane_com.setAlignment(Pos.CENTER);
        pane_com.setHgap(20);
        pane_com.setVgap(10);
        pane_com.setMinSize(200, 60);

        TitledPane pane_01 = new TitledPane("聊天窗口(当前用户:"+user.getUserName()+")",pane_com);
        pane_01.setCollapsible(false);

        ta_info = new TextArea();
        ta_info.setMinSize(500, 390);
        ScrollPane pane_info = new ScrollPane(ta_info);

        GridPane pane_02 = new GridPane();
        pane_02.add(pane_info,0,0);
        pane_02.add(listView,1,0);


        VBox box = new VBox(pane_02,pane_01);
        box.setSpacing(10);
        box.setAlignment(Pos.CENTER);

        Scene scene = new Scene(box);
        stage.setScene(scene);
        stage.setTitle("在线用户列表，来自1707");
        stage.show();
    }

    public void init(){
        observableList = FXCollections.observableList(onlineUser);
        listView = new ListView<>(observableList);
        listView.setItems(observableList);
        new Thread(()->{l();}).start();
    }

    public void showFileDownStage(ArrayList arr){
        GridPane pane_com = new GridPane();
        Button btn_down = new Button("下载");

        ObservableList oblist = FXCollections.observableList(arr);
        ListView lv = new ListView<>(oblist);
        lv.setItems(oblist);
        pane_com.addRow(1,lv);
        pane_com.addRow(2,btn_down);
        GridPane.setHalignment(btn_down,HPos.CENTER);
        VBox box = new VBox(pane_com);
        box.setSpacing(10);
        box.setAlignment(Pos.CENTER);
        Scene scene = new Scene(box);
        Stage stage = new Stage();
        stage.setScene(scene);
        stage.setTitle("在线用户列表，来自1707");
        stage.show();
    }

    public void listFile(ActionEvent event){
        try (
            SSLSocket s = (SSLSocket) factory.createSocket(ClientInfo.serverAddr, ClientInfo.serverPort);
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
        ){
            Message msg = new Message();
            msg.setMsgType(MessageType.MSG_LIST_FILE);
            msg.setFromUser(user.getUserName());
            oos.writeObject(msg);
            oos.flush();
            msg = (Message) ois.readObject();
            ArrayList<String> arr = (ArrayList) msg.getContent();
            for (String name:arr){
                System.out.println(name+"\n");
            }
            showFileDownStage(arr);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public void sendFile(String username){
        File file = fileChooser.showOpenDialog(new Stage());
        try (
            //创建SSL socket
            SSLSocket s = (SSLSocket) factory.createSocket(ClientInfo.serverAddr, ClientInfo.serverPort);
            //注意：先创建输出流对象，再创建输入流对象，服务器则相反
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        ){
            Message msg = new Message();
            msg.setToUser(username);
            msg.setFromUser(user.getUserName());
            msg.setMsgType(MessageType.MSG_PUT_FILE);
            msg.setContent(file.getName());
            oos.writeObject(msg);
            OutputStream fos =  s.getOutputStream();
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int length;
            while((length = fis.read(buffer, 0, buffer.length)) != -1) {
                dos.write(buffer, 0, length);
                dos.flush();
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public void sentTo(String username){
        try (
            //创建SSL socket
            SSLSocket s = (SSLSocket) factory.createSocket(ClientInfo.serverAddr, ClientInfo.serverPort);
            //注意：先创建输出流对象，再创建输入流对象，服务器则相反
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
        ){
            Message msg = new Message();
            msg.setToUser(username);
            msg.setFromUser(user.getUserName());
            msg.setMsgType(MessageType.MSG_TRAN);
            msg.setContent(user.getUserName()+":\n"+tf_msg.getText());
            oos.writeObject(msg);
            msg = (Message) ois.readObject();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public void l(){
        while (true){
            try{
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                Message msg = (Message) ois.readObject();
                if (msg.getMsgType()==MessageType.MSG_TRAN) {
                    if(msg.getContent() instanceof String) {
                        String str = (String) msg.getContent();
                        ta_info.appendText(str + "\n");
                    }
                }

                if (msg.getMsgType()==MessageType.MSG_PUT_FILE){
                    ta_info.appendText(msg.getFromUser()+":\n"+"收到"+msg.getFromUser()+"传输的文件，请在接收窗口接收\n");
                }

                if (msg.getMsgType()==MessageType.MSG_FLUSH){
                    onlineUser = (ArrayList) msg.getContent();
                    onlineUser.remove(user.getUserName());
                    Platform.runLater(()->{
                        observableList = FXCollections.observableList(onlineUser);
                        listView.setItems(observableList);
                    });
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }

    public boolean connect (){
        try {
            socket = new DatagramSocket();
            SocketAddress endpoint = new InetSocketAddress(ClientInfo.serverAddr,ClientInfo.serverDataPort);
            socket.connect(endpoint);
            return true;
        } catch (IOException ex) {
            System.out.println("异常信息："+ex.getMessage());
            return false;
        }
    }

    public void btnDisconnectHandler(ActionEvent event){
        if (socket != null)   socket.close();
    }

    public void btnSendHandler(ActionEvent event){
        String msg_sent = tf_msg.getText();

        try {
            DatagramPacket pout  = new DatagramPacket(msg_sent.getBytes(),msg_sent.getBytes().length);
            socket.send(pout);

            System.out.println(MyUtils.getCurrentTimeString() + ",向服务器发送字符串:"+msg_sent);
            ta_info.appendText(MyUtils.getCurrentTimeString() + ",发送信息给服务器："+msg_sent+"\n");

            DatagramPacket pin = new DatagramPacket(new byte[512],512);
            socket.receive(pin);

            //socket收到的数据的长度不一定是pin包定义的数组的大小的，可以通过pin.getLength()取得接收到的数据的长度。
            //将接收到的数据转换成字符串时，可以设定从包里取多少数据，如下：
            String msg_recv=new String(pin.getData(),0, pin.getLength());

            System.out.println(MyUtils.getCurrentTimeString() + ",从服务器接收回送字符串:"+msg_recv);
            ta_info.appendText(MyUtils.getCurrentTimeString() + ",从服务器接收信息："+msg_recv+"\n");

        } catch (IOException ex) {
            System.out.println("异常信息："+ex.getMessage());
            MyUtils.showAlert("连接服务器或发送信息出错！");
        }
    }
}
